#include"LFSR.h"
#include"global.h"
#include<vector>
#include<string>
#include<bitset>
#include<tuple>
#include<iostream>
using namespace std;
//f=1+c1x+...
vector<uint8_t> LFSR::generate(vector<uint8_t> f,vector<uint8_t> seed,int size)
{
	vector<uint8_t> rel(seed);
	//for(auto &e:rel)cout<<xmap[e];cout<<endl;
	//cout<<rel.size()<<endl;
	while(rel.size()<size)
	{
		uint8_t a=0;
		for(int i=1;i<f.size();i++)
		{
		//cout<<"i:"<<i<<" size:"<<f.size()endl;
			//cout<<'\n'<<xmap[f[i]]<<' '<<xmap[rel[rel.size()-i]]<<endl;
			a^=(f[i]&rel[rel.size()-i]);
		}
		rel.push_back(a);

	}
	for(auto &e:rel)cout<<xmap[e];
	cout<<endl;
	return rel;
}
//
const array<vector<uint8_t>,15> fx={
vector<uint8_t>{1},
vector<uint8_t>{1,1},
vector<uint8_t>{1,1,1},
vector<uint8_t>{1,1,0,1},
vector<uint8_t>{1,1,0,0,1},
vector<uint8_t>{1,0,1,0,0,1},
vector<uint8_t>{1,1,0,0,0,0,1},
vector<uint8_t>{1,1,0,0,0,0,0,1},
vector<uint8_t>{1,1,0,0,0,1,1,0,1},
vector<uint8_t>{1,0,0,0,1,0,0,0,0,1},
vector<uint8_t>{1,0,0,1,0,0,0,0,0,0,1},
vector<uint8_t>{1,0,1,0,0,0,0,0,0,0,0,1},
vector<uint8_t>{1,0,0,1,1,0,0,1,0,0,0,0,1},
vector<uint8_t>{1,1,0,1,1,0,0,0,0,0,0,0,0,1},
vector<uint8_t>{1,1,0,0,0,0,0,0,0,0,0,1,1,0,1}
};
vector<uint8_t> LFSR::get(int order)
{
	vector<uint8_t> seed(order,0);
	return generate(fx.at(order),seed,1<<order-1);
}
tuple<bitset<MAX_ORDER+1>,int> LFSR::synthesis(vector<uint8_t> data)
{
	cout<<"\ninput data(l="<<data.size()<<"):"<<endl;
	for(auto &e:data)cout<<xmap[e];
	vector<uint8_t> d(data.size());
	vector<uint32_t>	l(data.size()+1);
	vector<bitset<MAX_ORDER+1>> f(data.size()+1);
	//first step
	uint32_t n0;
	for(n0=0;data[n0]==0;n0++)
		d[n0]=data[n0];
	for(int i=1;i<=n0;i++)
	{
		f[i][0]=1;
		l[i]=0;
	}
	l[n0+1]=n0+1;
	f[n0+1].reset();
	f[n0+1][0]=1;
	f[n0+1][n0+1]=1;
	//second step
	for(int n=n0+1;n<data.size();n++)
	{
	//dn
		uint8_t _d=0;
		for(int i=0;i<=l[n];i++)
			_d^=(f[n][i]*data[n-i]);
		d[n]=_d;

		if(d[n]==0)
		{
			f[n+1]=f[n];
			l[n+1]=l[n];
		}
		else
		{
			int m=n-1;
			while(l[m]==l[m+1])
				m--;
			f[n+1]=f[n]^(f[m]<<(n-m));
			l[n+1]=max(l[n],n+1-l[n]);
		}
	}
	cout<<"\nf(x)(l="<<l[data.size()]<<")\n[c1 c2 c3 ... cn]:"<<endl;
	for(int i=1;i<=l[data.size()];i++)
	cout<<f[data.size()][i];
	cout<<endl;
	//cout<<"f:"<<f[data.size()]<<endl;

	return make_tuple(f[data.size()],l[data.size()]);
}

